Almost independent logically integrated license enforcement framework

ABSTRACT

A method of automatically transforming a computer program in order to control it&#39;s execution in compliance with the end user license agreement and concealing the program logic. The method allows even for distributing program&#39;s source code and still enforcing the license. In particular the execution control allows for managing the period of time and the number of times a particular instance of a program was run as well as for detecting the fact of a simultaneous execution of the same instance by several users. Allows for a very infrequent outside interaction with a secure program such that only a certain percentage of program executions causes outside connection, and no more than a fixed number of times per each such execution independently of the input data size. For each outside interaction allows for an extremely simple and independent of the client input data size secure program processing.

FIELD OF THE INVENTION

[0001] The invention is in the field of computer software piracy protection.

BACKGROUND OF THE INVENTION

[0002] Computer software piracy is known to be a major source of not only the revenue loss but also the loss of competitive advantage and intellectual property. Therefore a great diversity of software piracy protection systems was introduced.

[0003] Such systems usually control the period of time a computer program can be functioning for or the number of times it can be executed or limit the program's functionality. This is usually the case with the trial versions of software. Such protection systems can also control the number of users simultaneously executing a program for a given license.

[0004] A number of ways to implement such systems currently exists. Those can be grouped into three categories: one where a program runs completely within the user's computer—which we'll call closed systems and the systems that interact with the external environment—we'll call them open systems. Open systems include various types of hardware dongles, network based registration, client-server configurations where a portion of code is executed on a secure remote server. Closed systems range from the simpler systems that monitor the system date or computer name and IP address to the sophisticated checking of hardware properties such as BIOS, CPU and hard drive properties in order to identify the computer. There are also many systems that combine the properties of both open and closed systems which we'll call hybrid systems such as Microsoft's Windows and Office XP copy protection system.

[0005] At the same time it is a known fact that a closed system cannot be fully protected from unauthorized use in principle. This is because of the fact that no matter what sophisticated checks the program makes it's executable code can be reverse-engineered into the source code and the results of the checks traced to the license control statements. Some protection systems however avoid this by integrating the checks into the critical code. Such systems can be circumvented by using a replay attack where all the queries the program makes to the operating system are recorded and than replayed. The same problem is with most hybrid systems—if their outside queries are independent of the critical data, a replay attack that simulates an external connection can allow to disable them as well. On the other hand the open systems dependent on a secure server, which executes some of its code—client-server setup, can possess a very powerful protection, however this set up currently presents a compromise between the level of program protection—how much of the logically critical code runs on a client side vs. the secure server load and frequency of an outside connection.

[0006] The current systems provide either a poor code protection—only rarely executed code runs on server side or resort to client-server processing where the server has to process the amount of data dependent on the particular problem size.

[0007] This approach means that if a software vendor sells a lot of copies of some computationally intensive application to a large number of clients, then the vendor's server will be accessed every time a client runs the application. If a particular client also processes large amounts of homogeneous data such as database records or for example media files or spreadsheets then a certain, most likely critical portion of code will be executed as many times as there are such records. This means that the secure server will be executing some code for every single record the client processes. Such overhead on the server side, also given the slowness of the networks quickly becomes prohibitive. In addition to this the need to maintain a high speed outside connection becomes a serious inconvenience for the clients.

[0008] Another advantage this invention offers is an ability to provide an existing market for hardware dongles with a way to prevent the client program from getting stripped of the code that controls it's execution by communicating with the dongle. In this scenario, the secure program will reside on a dongle and since it requires very little processing time it does not require any powerful processor on the dongle.

SUMMARY OF THE INVENTION

[0009] This invention allows at the same time to securely conceal the program's logic in such way that reverse-engineering is pointless, control the program execution depending on the license agreement and also allows to maintain a very infrequent outside connection with a small data packet sent and returned with each connection. This means that only for a given pre-defined percentage of program executions the outside secure program can be contacted. Such contact will also be only once per execution.

[0010] The transmission in this case is independent of the problem size and the processing required by the secure program is extremely simple and independent of the problem size as well. Such transmission can be compared to a simple TCP/IP “ping” command. This allows to have any number of clients executing software of any complexity on their own high-end computers almost independently of the outside connection. The packet sent to the secure program presents no privacy concerns since the information it contains represents only a slice of data processed on the client computer in such way that there is no way restore the data itself.

[0011] The base concept of this invention is that in order to adequately reflect complexity of any non-trivial algorithm one must definitely include all of it's logical conditions that control the flow of data. Based on this premise the main objective therefore becomes protection of these conditions, which this invention persuades. This allows for both upholding the license agreement and concealing the program logic. To this end this invention provides a way of aggregating the program conditions and ensuring the sufficient number of Boolean variables in order to effectively resist brute force attacks. It also combines the conditions that relate only to the base program logic with certain Boolean expression that are almost always true except for a given percentage of inputs. This allows controlling the frequency of the outside connection for a given condition execution.

[0012] This invention also provides a mechanism for ensuring that independently of the input data size the outside connection will be established with a fixed up-front frequency. This is achieved by a special transformation of program loops and conditions within them to ensure that all loops are recursive and using that to reliably establish the difference between the first set of iterations and the later ones in order to produce the controlled fault only once in the beginning of the loop execution.

[0013] Another concept of this invention is license violation trapping. Given the program is fully reverse-engineered it is impossible to have a separate condition to trap the cases when the client license is invalid. This invention produces controlled faults originating from the functionally necessary logical conditions. This is believed to be the only way of effectively resisting code analysis. Since if the program terminates immediately a special termination condition gets revealed. Instead such faults cause the program to incorrectly alter the execution flow by taking legitimate branches under the deliberately wrong conditions.

[0014] This also allows to ensure that after such controlled fault takes place the program can immediately recover from it by obtaining a correct value of such condition from the secure server.

PRIOR ART

[0015] Distributed Execution Software Licensing Server,

[0016] Clark Jonathan application # 20010011254

[0017] The protection of computer software: its technology and applications.

[0018] Derrick Grover, 1992

DRAWING FIGURES

[0019]FIG. 1 shows a high level program transformation steps

[0020]FIG. 2 shows protected program functioning

[0021]FIGS. 3.1-3.2 gives a high level view of the Blending Procedure

[0022]FIG. 4 shows a sample technique of converting an independent loop to a recursive one using secret key encryption

[0023]FIG. 5 shows the algorithm decomposition

[0024]FIG. 6 shows the condition protection inside the recursive loop

[0025]FIGS. 7.1-7.3 shows the initial code transformation

DETAILED DESCRIPTION OF THE INVENTION

[0026] Let A is some algorithm (FIG. 5.2), D is it's input data (FIG. 5.6), TIME(A,D) is the time it takes A to process D. We shall denote client program as C (FIG. 5.3) and secure program as S (see FIG. 5.4) and communication channel Z (FIG. 2.8). The client license for A we denote as LS(A) (see FIG. 5.8) and call it a set of statements regulating whether or not, how long, how many times a particular client can use A.

[0027] Our objective is to distribute A in such way that:

[0028] a) A is executed almost entirely by client program and almost always independently of any external components;

[0029] b) LS(A) must be adhered;

Almost entirely means that if A=A ₁(D)∪A ₂(E(D))   (1),

[0030] where A₁ and A₂ are understood as instruction sets, A₁ is executed on C and A₂ on S (FIG. 5.5), E is some algorithm executed by C which prepares some data slice the size of O(1) for processing on S, then TIME(E) and TIME(A. ) are O(1) (independent of n). This also means that communication channel Z is used with a frequency and load independent of n as well.

[0031] At the same time b) dictates that there must be no polynomial time algorithm F:F(A₁, E , A₂ E(D))=A, (see FIG. 5.10).

[0032] To that end we do the following:

[0033] Part 1: Initial Code Transformation

[0034] Transform A to achieve iterator and conditional aggregation. Following is a C++ resembling pseudo-code of these transformation steps:

[0035] a) Translation of recursive function calls into while loops (FIG. 1.1). Let Fn( ) is a recursive function represented as:

[0036] Fn {a; b; (c ? return); Fn( ); d; e; f;}—FIG. 7.1.1.

[0037] We transform it to:

[0038] while (c) (a; b; Stack.add(input(d), input (e), input (f)))) while (Stack.pop) (d; e; f;)—FIG. 7.1.2

[0039] Here input(t) is the input data for function or an instruction set t( ).

[0040] b) Local variable globalization to allow for the aggregation (FIG. 1.15). Let Fn( ) and Gn( ) are two functions across which we globalize the variables:

Fn{a; (c?Gn(d):Gn(e)); f}; Gn(p){g; (h?i(p):j(p)); k) (see FIG. 7.2.2)→

→Fn{a; Gn( ); f}; Gn{c?c&h?i(d); c&!h?j(d); !c&h?i(e); !c&!h?j(e)}(see FIG. 7.2.1)

[0041] c) Diversification of nested conditions (FIG. 1.16). We Substitute

C(b1, b2, b3)→T(s1, s2, s3, . . . ), where s1=s1(b1, b2, b3, b1, b2, b3), s2=s2( . . . ),

[0042] . . . are some Boolean expressions.

[0043] This helps in case such as:

c1(a, b, c) . . . d=f( . . . ) . . . c2(a, b, c, d) . . . e=g( . . . ) . . . c3(a, b, c, d, e)=c2(a, b, c, d) & e . . .

[0044] In this case the fact that c2 was used prior to c3 can lead to an easy guess about the structure of c3—

[0045] this can be blended if different tautologies are introduced in place of c1 and c2 . . . E.g.: given a simple a & !b→(a, b, !a, !b)→p=(a∥b) & !a, q=(a∥!b) & b & a∥a,→(a, b, !a, !b, p, q)→(s∥!s) & (a & !b) to be equivalently transformed; here s(a, b, !a, !b, p, q) is another Boolean expression.

[0046] d) Loop condition transformation and aggregation (FIG. 1.2):

[0047] while (c) (a; b?d:e; f) (see FIG. 7.3.1)→

→while (t)(!c? break; c?a; (c&b)?{d; f}; (c&!b)?{e; f}) (see FIG. 7.3.2)

[0048] in this way, also, multiple loops are translated into one.

[0049] Based on this preprocessing we are now in position to define the decomposition (1)

[0050] For an identified set P of logical conditions crucial to A and any SεP we replace S with a new Boolean condition C″=S & F, where F is such that F=f in q % of cases. Such set P could be automatically chosen to include the longest Boolean conditions obtained as a result of Part 1.

[0051] Part 2: Random Condition Controller (RCC) and Useful Boolean Systems

[0052] Let B(r) is a k dimensional space of Boolean vectors, S and F are Boolean functions on B(r). LetσεB(r) be a Boolean vector an argument for S, and p a probability. Consider F=P(p, σ), where P is a Boolean expression to be defined below. We make sure that such expression can be represented as a single formula (not a system) with the length no greater than a linear function of r, for exmple: $\begin{matrix} {{P\left( {p,\sigma} \right)} = {\begin{matrix} \left\lceil {\log_{2}\left( {1/p} \right)} \right\rceil \\ \bigvee\limits_{j = 1} \end{matrix}\sigma^{j}}} & (3.0) \end{matrix}$

[0053] We can manipulate the probability p more freely if we consider a conjunction of multiple RHS(3.0) expressions each one with a unique combination of negations assigned to each σ^(j) and having different upper bounds in the disjunction. In this case the total probability will be the sum of probabilities for each RHS(3.0) term.

[0054] For future use we note the following systems.

[0055] Comparison of two Boolean vectors: $\begin{matrix} \left. \left( {x > y} \right)\Leftrightarrow{\overset{r}{\bigvee\limits_{i = 1}}\left( {\left( {x_{i}\bigwedge y_{i}} \right)\bigwedge\left( {\overset{r}{\bigwedge\limits_{j = {i + 1}}}{\left( {x_{j}\bigwedge y_{j}} \right)\bigvee\left( {x_{j}\bigwedge y_{j}} \right)}} \right)} \right)} \right. & \left( {3.0{.1}} \right) \end{matrix}$

[0056] Here the RHS basically says: there must be at least one bit (i) such that x_(i) is True y_(i) is False, and all higher order bits are equal.

[0057] Summation for positive integers in Boolean form:

z′ _(k)=(x _(k)

y _(k))

(y _(k)

x _(k))—sum without carry over values   (3.1.1)

v _(k)=(x _(k)

y _(k))

(v _(k−1){circumflex over ( )}(x _(k)

y _(k)))—carry over values   (3.1.2)

z _(k)=(z′ _(k)

v _(k−1))

(v _(k−1)

z′ _(k))—final sum   (3.1.3)

v₀=f   (3.1.4)

[0058] E.g.: when x_(k)=y_(k) we have:

z′ _(k) =f, v _(k) =x _(k)

(v _(k−1)

x _(k)), z_(k) =z _(k−1)—final sum is just a shift   (3.1.5)

[0059] In a similar fashion we obtain subtraction:

z _(k)=(x _(k)

y _(k)

v _(k))

(x _(k)

y _(k)& v _(k))∥  (3.2.1)

(x _(k)

y _(k) v _(k))

(x _(k)

y _(k)

v _(k))—final difference

v _(k)=(v _(k−1)

x _(k−1))

(x _(k−1)

y _(k−1)

v _(k−1))∥

(x_(k−1)

y _(k−1)

v _(k−1))—carry over values   (3.2.2)

[0060] Now, represent xy=z in Boolean form.

[0061] System for product is based on a conventional “pencil and paper” rule combined with (3.1):

[0062] Let q=f, if j<k and q_(k) ^(j)=y_(k)

x_(j−k+1), otherwise. Also let s^(k)=s⁻¹+q_(k) which we'll represent in Boolean form. Combined with (3.1) the following system is obtained:

z′ _(j)=(s _(j) ^(k−1)

q _(k) ^(j))∥(q _(k) ^(j)

s _(j) ^(k−1))   (3.3.1)

v _(j)=(s _(j) ^(k−1)

q _(k) ^(j))∥(v _(j−1)

( s _(j) ^(k−1)∥q_(k) ^(j)))   (3.3.2)

s _(j) ^(k)=(z′ _(j)

v _(j−1))∥(v _(j−1)

z′ _(j))—partial sum   (3.3.3)

q_(k) ^(j=y) _(k)

x_(j−k+1), for j k—partial product (3.3.4)

q_(k) ^(j)=f, for j<k   (3.3.5)

z_(j)=s_(j) ^(r)—final result   (3.3.6)

v₀=f,j<r+k   (3.3.7)

[0063] Here j is the column index—indicating bits and k is the row index—indicating partial products. In (3.1),(3.2) and (3.3) k=1 . . . r.

[0064] Also for future use define operators I:I $(\sigma) = {{\sum\limits_{\mu = 0}^{r - 1}\quad {\sigma_{\mu}2^{\mu}\quad {and}\quad B}} = {I^{- 1}.}}$

[0065] Comment 1 When converting a Boolean system that has a recursion to an inline expression the length of such expression can become exponential of the number of variables in case a previous recursion step variable is used in multiple instances. This is the case with (3.3) but is not with (3.0) and (3.1).

[0066] Comment 2 Evidently many other ways in addition to (3.0) of constructing expressions that are true with a given probability exist. Such as considering Boolean representation of σ=(0)mod(σ₀) for some predefined key σ₀. A multidimensional analog of this can be considered as well. In this case F will be true if and only if a random point taken within a hypercube lands on a mesh node. Such mesh will have nodes evenly spread apart, which will represent divisibility by σ₀ condition.

[0067] Comment 3 When selecting the upper and lower limits for the desired probability level, one should note that σ is not evenly but logarithmically distributed according to the Benford's law.

[0068] Comment 4 q has a lower limit imposed by dim(B(k))=k and thus by the number of variables in S.

[0069] Comment 5 In order to address Comment 4 problem, dim(B(k)) can be increased by introduction of “similar” variables e.g. if initially b=(a<3) then we add b1=(a=3); b2=(a>3); b3=(a<2) and etc (see FIG. 1.5). This method may involve manual steps and may not be required for the recursive processing conditions.

[0070] Part 3: Recursive Processing

[0071] This part defines the context for part 2 within the code. First we need to draw a distinction between independent and recursive input data D.

[0072] Definition 1. We call D recursive relative to a specific code segment S if at least some part of D is generated by a single starting value d and the generating function is S, otherwise we call it independent.

[0073] Comment 6. Recursive property of S is critical since it allows utilizing the dependency of the next step from the current one for the purposes of identifying a single monolithic execution.

[0074] Consider a code fragment for some recursive input data (see FIG. 6.7):

p ₀ =I(d ₁) while(L(p _(k))){(C(p _(k)))?{d _(k+1) =t(d _(k))}:

{d _(k+1) =f(d _(k)); p _(k+1)=Evaluate (d _(k+1))}  (4)

[0075] where p_(k) is a Boolean vector of dimension D, L(p_(k)) is a loop condition (see FIG. 6.2), k is the loop index, C(p_(k)) is an inner loop condition (see FIG. 6.1), t( ) and f( ) are some non-recursive functions or more generally, two instruction sets (see FIGS. 6.3 and 6.4). They are non-recursive because according to Part 1 recursive function handling and conditional aggregation includes recursive loop conditions into L and C. Evaluate( ) is a function that returns Boolean vector based on the processed loop data (FIG. 6.10).

[0076] If |D|<s (see definition of s below), we require that t(.) and f(.) were chosen so that they mainly contain the logic related to calculating d_(k+1) based on d_(k) and other data associated with d_(k+1). More precisely we require that t(.) and f(.) may be executed out of sequence irrespectively of the value of C(p_(k)). For example such requirement rules out the use of some communication protocol functions as t(.) and f(.). It is important to note that the correct sequence will be established no more then a fixed O(1) number of steps away from the redundant call of t(.) or f(.). Therefore a sequence correction may be issued for such outside communication. As described by Part 1 c), d) this gets transformed into:

p ₀ =I(d ₁) while (true){(L(p _(k)))?(exit loop):(continue); (L(p _(k))

C(p _(k)))?

{d _(k+1) =t(d _(k))}:{d _(k+1) =f(d _(k))}; p _(k+1)=Evaluate (d _(k+1))}  (5)

[0077] Denote 'C(p_(k))=L(p_(k))

C(p_(k)) (see FIG. 6.5). Also assume certain security level s such that performing some operations 2^(s) times is not feasible (e.g. s=75) and introduce a number g=[s/D].

[0078] The intruder's objective is to remove F and always correctly run 'C. In order to resist this, our objective now is to satisfy the following requirements (*):

[0079] a) Conceal real Co.

[0080] b) Produce a controlled malfunction in every q % of cases in the very beginning of the process.

[0081] c) Recover from this malfunction immediately by use of DSR (see below)—this means using some exception trapping technique (FIG. 6.6).

[0082] d) Ensure that this technique does not help in identifying the proper processing logic for 'C( ).

[0083] e) Rule out the possibility of directly substituting some variables with their calculated values.

[0084] f) Eliminate the possibility of guessing the correct value of 'C( ) by adding multilevel malfunctioning with the depth d.

[0085] g) Resist the brute force attack where the truth table of 'C(.) can be fully constructed.

[0086] To this end we shall show that the following code segment is equivalent to (4) in (100-q) % of cases and satisfies the above constraints.

[0087] We shall say that a Boolean expression Q(p_(k)}) significantly depends on {p_(k)} if there is no such subset of variables in {p_(k)} that Q({p_(k)}) is independent of.

[0088] In order to satisfy constraint b) we need the main expression to function without invoking RCC a fixed number of steps after the loop start. The loop start is identified by not having any of the prior steps and therefore the first step is non-recursive.

[0089] This is the main critical property of start that we'll use. One of the central objectives is to ensure that RCC-free execution may not be adopted to run at start as well. To this end we segregate out a special condition that can only execute if d of the previous evaluations were performed. It is also critical that such condition significantly depends on these previous steps in order to rule out the possibility of forging these steps with any RCC-free data. In other words we need to transform a single step recursion into a multi-step one.

[0090] We also need to satisfy f) and therefore we consider d evaluations in the beginning as our “start”.

[0091] At the same time g) dictates that all steps must depended on at least s variables, including the first step. Such dependency must also be significant. Otherwise if a subset of significant variables is isolated, then even without constructing a truth table for the new artificial variables, the truth table for the whole expression can be created. This is insured by an application of Loop Variable Increment Procedure prior to the next step (5).

[0092] Let also T is some test expression, unrelated to C, which we'll use for exception trapping. Exception trapping gets activated if RCC has fired.

[0093] We shall now replace (4) with the following set of code segments (6): p₀ = I(d₀) // compute first Boolean vector p based on the initial input data D // initial evaluation I( ) is considered generally different from the recursive evaluation BL(F(p₀), C(p₀))?(d₁ = t(d₀)) : (d₁ = f(d₀)) (BL(F(p₀), T (p₀)) ≠ T (p₀) ) ? (DS Request) : (continue) (6.1) p₁ = Evaluate(d₁) k:=1

[0094] The code fragment above we call the Initial Main Clause, shown as FIG. 6.9.

While (j<d){c ^(j) ₁=α_(j)(p ₁ , p ₀)

RCC(p₀)}

[0095] The line above is the Exception Trapping Clause, shown as FIG. 6.6. While (True) { V(p_(k), p_(k−1)) = ĵ (c_(k) ^(j){circumflex over ( )}α_(j) (p_(k), p_(k−1)))

)┐c_(k) ^(j) {circumflex over ( )}┐α_(j)(. . .)) // The above expression for V( ) is not to be actually included in the code - it is to be retained // in the blended expression s below If BL(V(. . .){circumflex over ( )}C(p_(k)))d_(k+1) = t(d_(k)) (FIG. 1.12) (6.2) Else d_(k+1) = f(d_(k)) p_(k+1) = Evaluated(d_(k+1)) While (j<d) {c_(k+1) ^(j) = α_(j)(p_(k+1), p_(k)) {circumflex over ( )}V(p_(k), p_(k−1))} (FIG. 1.11) k:=k+1 }

[0096] This code fragment we call the Recursive Main Clause, shown as FIG. 6.8.

[0097] The key to disrupting this one would be locating an appropriate p_(k−1) so that the unknown V(p_(k), p_(k−1)) is true and the certificate values can be calculated. So for a given starting (disrupting) p_(k) one would need to get any p_(k−1) such that c^(j) _(k=α) _(j)(p_(k), p_(k−1)) for any applicable c^(j) _(k). One could select p_(k−1) at random and then wish to compute c^(j) _(k). The problem would then be with the fact that α_(j) is also not known and again comes in bundled with the previous V( ). This process now becomes recursive and the only other remaining end would be the initial RCC—which is what we want.

[0098] Satisfaction of other constraints also follows from the above construction.

[0099] Here we have omitted the loop itself with the other loop related condition for brevity.

[0100] Remarkably, code segment (6) allows to establish significant dependency of all iteration steps on the first step, without involving any properties of the recursive functions t( ) and f( ).

[0101] Complexity of the inverse transformation is now insured by the secure level s and efficiency of the blending procedure BL. FIG. 1.17 shows the place of Blending Procedure in the flow.

[0102] Part 4: Independent Processing (FIG. 1.13)

[0103] Independent processing itself lacks the critical property noted in Comment 6 and therefore one cannot clearly distinguish between the code that executes twice and processes 2n data records and two executions that process n records each from different record sets.

[0104] An attack that exploits the lack of steps interdependence would consist of adding a set of m=d Boolean vectors H for which the code (6) has already been correctly executed and the certificates {c_(k−j)} were already generated. Such strategy we'll call H-strategy. H-strategy would allow the attacker to eliminate a chance of an RCC filing within the first m steps—which is the only time it is allowed to fire.

[0105] In order to compensate for this, we artificially convert the independent code segment to a special recursive form in an exponentially difficult to invert way and introduce a certain processing sequence that would make adding such elements H impossible.

[0106] We are now given:

while (true) {(L(p_(k)))?(exit loop):(continue); ('C(p_(k)))?

{t(d _(k)); }:{f(d _(k)); }}, 'C(p _(k))=L(p _(k))

C(p _(k))   (5.b)

[0107] Here let p_(μ)={p_(μτ)}, τ=1 . . . L, μ=1 . . . n and n>>m, n depends on user data batch size and m is only defined by the program structure and k is the loop index.

[0108] Since the processing is independent we can process {p_(μ)} in any sequence. Let ζ(p_(μ))={ζ_(τ)(p_(μ))}τ=1 . . . L is some Boolean system which solution represents a 3-SAT problem such that the map ζ(.) is bijective and: {p_(μ)}→{'e_(μ)}, 'e_(μ)=ζ(p_(μ)). It is also easy to verify that a given 'e_(μ) was obtained via the application of ζ(.):

'e _(μ)

ζ(p _(μ))≡t   (9)

[0109] Using this we order {'e_(μ)} by I('e_(μ)) values and remove all duplicate elements in order to eliminate multiple replay of the same step in the intruder's attack. The fact that ζ(.) is bijective will ensure that removal of duplicate {'e_(μ)} will mean the removal of duplicate {p_(μ)} and only those.

[0110] An example of bijective ζ(.) is presented in Section B.1.

[0111] We shall now do the processing in a new way—we will be processing two steps as a one, under a common Boolean condition. Instead of considering four regular conditions:

'C(p_(k))?(t(d_(k))), ┐'C(p_(k))?(f(d_(k))), 'C(p_(k+1))?(t(d_(k+1))), ┐'C(p_(k+1))?(f(d_(k+1))),

[0112] we shall consider four new ones:

'C(p_(k+1))

'C(p_(k))?(t(d_(k+1)); t(d_(k))), ┐'C(p_(k+1))

'C(p_(k))?(f(d_(k+1)); t(d_(k))),

'C(p_(k+1))

┐'C(p_(k))?(t(d_(k+1)); f(d_(k))), ┐'C(p_(k+1))

┐'C(p_(k))?(f(d_(k+1)); f(d_(k))).

[0113] The loop execution will be described in form of these pairs: we start with μ=([n/2], [n/2]+1) for step 1, this element we'll denote γ. Step 2 will process p with index

B(2)=([n/2]−1, [n/2]+2),

[0114] step 3: B(3)=([n/2]-2, [n/2]+3) and etc. until all elements are processed. Such sequence we'll call Bootstrap Sequence or B-sequence and we'll say it consists of {γ_(k)}, where γ=γ₀ and γ_(k)=e.

[0115] We shall enforce B-sequence by requiring that B₁ (k+1)<B₁ (k) and B₂ (k+1)>B₂ (k) within the main condition itself. A Boolean function that checks each of these inequalities we denote Ψ which will be based on expression (3.0.1).

[0116] Such processing sequence ensures that in order to process H elements in the beginning, they would have to be inserted in the vicinity of γ between the first two real elements that need to be processed, in such way that H∩{p_(μ)}=Ø. Otherwise if RCC would fire while processing γ . . . γ_(m) it would also fire while processing h₀. . . h_(m). Such insertion would result in “sacrificing” some of {p_(μ)} elements since B-sequence is expanding and once any p_(μ) is skipped it can no longer be processed. Even though such step may be possible in certain cases, this is not the main obstacle. In order to establish hεH such that

[0117] ζ(h)ε(I(p₁), I(p_(u))) one would have to attempt solving all systems ζ(h)=α for all αε (I(p₁), I(p_(u)) such problem is not just NP-complete. There is no guarantee that such solution can be found at all. Moreover, such solution will need to be found m times in order to determine all elements of H which is almost certainly impossible.

[0118] In case with ζ(.) from Section B.1 the solution can be found via the inverse matrix. This however provides almost no benefit to the intruder since H will have to be found for every set {p_(μ)} processed, which will trigger RCC on every attempt just as it would in any other case.

[0119] Also in order to increase the number of variables to a secure level s we will use the same method as in (6). This can certainly increase the number of Boolean expression evaluations 2^([g/2]) times, however Boolean expression evaluation is believed to be a relatively fast operation and should normally take negligible time in comparison to the execution of t(.) and It is also important to note that unlike (6) there will be no redundant executions of t(.) and f(.) due to the fact that all {p_(k)} are already known, and therefore all constraints on them can be lifted.

[0120] The new version of condition (6) will then also include verification for B-sequence as well as the check (9): While (Not all elements {d_(k)} are processed) { p_(k) = Evaluated(d_(k)) ′e_(k) ^(j) = ξ_(j)(p_(k)) } While (k<m) { (F(p_(k)){circumflex over ( )}′C(p_(k))))? (t(d_(k)); c_(k) = α^(t)(p_(k)); ):(f(d_(k)); c_(k) '2 α^(f)(p_(k)); ); (BL(F(p_(k)), T(p_(k))) ≠ T(p_(k))) ? (DS Request) : (continue) (8.a) }

[0121] Here we again combine F-RCC—with some T so that F remains secret in order to avoid letting the intruder know what values trigger RCC.

[0122] While (k≧m) { $\begin{matrix} {{{\left. {{BL}\left( {{{{\,^{\prime}C}\left( p_{k} \right)}\bigwedge\left( {\overset{k}{\bigwedge\limits_{j = {k - m}}}{\Psi \left( {{\varsigma \left( p_{j} \right)},{\varsigma \left( p_{k} \right)}} \right)}} \right)\bigwedge\left( {\overset{D}{\bigwedge\limits_{j = 1}}\left( {{{}_{}^{}{}_{}^{}}\bigvee{\varsigma_{j}\left( p_{k} \right)}} \right)} \right)\bigwedge\left( {{{\,^{\prime}C}\left( p_{k - 1} \right)}\bigwedge\left( {c_{k}\bigvee{\alpha^{t}\left( {p_{k},p_{k - 1}} \right)}} \right)} \right)}\bigvee\left( {{{\,^{\prime}C}\left( p_{k - 1} \right)}\bigwedge\left( {c_{k}\bigvee{\alpha^{f}\left( {p_{k},p_{k - 1}} \right)}} \right)} \right)} \right)} \right)?}\left( {{t\left( d_{k} \right)};{c_{k + 1} = {\alpha^{t}\left( {p_{k + 1},p_{k}} \right)}};} \right)}:\left( {{f\left( d_{k} \right)};{c_{k + 1} = {\alpha^{f}\left( {p_{k + 1},p_{k}} \right)}};} \right)} & \text{(7.a)} \end{matrix}$

[0123] The use of certificates here is critical in order to ensure that any “sacrifice” of some set in the vicinity of γ will lead to a failure in processing of all other elements: if the first m-steps are abandoned because they contain RCC and the next m are abandoned because they refer to the first m steps via ${\overset{k}{\bigwedge\limits_{j = {k - m}}}{\Psi \left( {{{}_{}^{}{}_{}^{}},{{}_{}^{}{}_{}^{}}} \right)}},$

[0124] then processing of all other steps might be possible if no certificates were used because all other steps will refer to the second set which is properly sequenced; however with the certificates this will not be possible because the certificate values will be needed for the second set as well as recursively for all other steps.

[0125] Comment 8 In order to ensure that the new processing sequence does not hinder the performance, two strategies are available:

[0126] Parallel preprocessing when a portion of input data is preprocessed first, in which case the main processing starts in parallel with the thread or process that prepares the next data portion.

[0127] Embedding preprocessed data into the input data outside the given application scope. This would be appropriate to do with media player applications where a distribution file will have such preprocessed data added before the distribution to the client so that the client application—the player—can skip this conversion step.

[0128] Part 5: Secure Data Preprocessing

[0129] The second part of Comment 8 is specifically applicable in cases where although the data processing is independent, the sequence is still important for other reasons. In this case {p_(μ)} can be encrypted recursively away from the client and processed on the client side without any change of sequence:

[0130] Introduce a Boolean encryption function E:

E(p _(μ) , p _(μ−1))={E _(ν)(p_(μ) , p _(μ−1))}={e _(ν) ^(μ) }=e, ν=1 . . . m.

[0131] This is in essence a logical system, which provides a bijective map with the inverse:

E ⁻¹(E(p _(μ) , p _(μ−1)), p_(μ−1))={E _(ν) ⁻¹(E(p _(μ) , p _(μ−1)), p _(μ−1))}=p_(μν) }=e,ν=1 . . . m.

[0132] As it's seen from this definition when we do the encryption we use the previous vector in order to encrypt the current one. When we decrypt we also have to use the previous unencrypted vector in order to decrypt the current one. By doing so we introduce recursion.

[0133] For a given 'C(p) we consider 'C(E⁻¹ (e^(μ), p_(μ−1))) 'C(p) and the code looks like:

('C(E⁻¹(e^(μ), p_(μ−1))))?(t( . . . )):(f( . . . ));

[0134] Note that unlike in (4), p_(μ) is calculated unconditionally (it is known initially), with no regard to the value of 'C( ). However this is not preventing us from using the protection scheme (6)-(8) since the certificates will still depend on the value of 'C(.).

[0135] Following is one of the ways that might be used to construct a Boolean system E with its inverse.

For m=dim(p) consider m ₀ <m:'m=m/m ₀ is integer (FIG. 4.1) and 'p={'p _(k)},

k=1 . . . 'm, where

'p _(k) ={p _(μ+k)} and here μ=1 . . . 'm ₀. Now consider an integer vector h (FIG. 4.2): ${\left\{ h_{k} \right\} = {\left\{ {I\left( {{}_{}^{}{}_{}^{}} \right)} \right\} = \left\{ {\sum\limits_{\mu = 1}^{{}_{}^{}{}_{}^{}}\quad {p_{\mu + k}2^{\mu - 1}}} \right\}}},$

k=1 . . . 'm. Choose integer matrix AεGL('m), i.e. dim(A)='m×'m, det(A) 0(FIG. 4.3).

[0136] This matrix represents a key secret to the end user. Based on this we define

E(p _(μ))=B(Ah _(μ) +h _(μ−1))=g _(μ)(FIG. 4.4). To obtain E ⁻¹ (g _(μ)) we consider

[0137] A⁻¹ (I(g_(μ))-h_(μ−1)) where when multiplying matrix by vector we replace all decimal numbers with Boolean vectors, all summations and subtractions here are replaced with the corresponding expressions over Booleans, multiplications are left in decimal form (FIG. 4.6), see (3.0) and (3.1).

[0138] In this way we can keep the expressions for carry over values v outside the main expression and avoid expanding recursion (see comment 1).

[0139] As a result we form a single logical expressions that depends on g and the coefficients of A⁻={v_(μj)}.

[0140] Comment 7 Since we cannot expect that A⁻¹ is also an integer matrix we'll have to estimate a precision of its elements and consequently the length of the corresponding Boolean vectors such that we can accurately restore p:

[0141] We'll estimate the smallest meaningful fraction 6 that may be added to the coefficients of A⁻¹ so that the result of multiplying the row of this matrix by h will produce a different integer. This smallest fraction will be the sought precision.

[0142] It follows from the definition that max({h_(k)})=2^('m) ₀ ⁻¹, and we assume that all 'm numbers in a row are positive. As it's easy to see under such conditions any coefficient precision error will be magnified to the greatest possible extent and ${\sum\limits_{j = 1}^{\,^{\prime}m}\quad {\left( {\underset{\mu \quad j}{v} + \delta} \right)2^{{\prime \quad m_{0}} - 1}}} - {\sum\limits_{j = 1}^{\,^{\prime}m}\quad {\underset{\mu \quad j}{v}2^{{\prime \quad m_{0}} - 1}}}$

1 when δ1/('m2^('m) ₀ ⁻¹) (FIG. 4.5).

[0143] This rounding step needs to be expressed in Boolean form (FIG. 4.8). Since (3.0) and (3.1) do not account for the decimal point, both input vectors can be multiplied by 2^(p+1), where 2^(p) is the desired rounding precision. This will convert the numbers to the regular Boolean vector case. The final result {z_(k)} will then simply have to be shifted back by re-indexing variables: k:=k−p. Since the vector before the encryption was integer we can be sure that z_(k)=t, for k<0. This completes the conversion to Part 4.

[0144] Comment 9: Data Specific Response (DSR)

[0145] Let d=(d), τ=1 . . . m, is the matrix of input vectors for C for the first m steps sent to the Licensing Server S. S checks the license database and if the license is valid, takes each d_(τ) and computes C(d_(τ)) and certificates {c_(k) ^(τ)} which are then returned to the client (FIG. 5.9). Once (C(d_(τ))) and {c_(k) ^(τ)} are received by the client it enables the execution of the first m steps. For step m+1 the certificates will be used correctly since the m'th step condition was evaluated properly using DS Response.

[0146] Part 6: Loop Variable Increment Procedure

[0147] This procedure is based on executing multiple steps as part of one iteration under some common logical conditions in order to increase the number of significant variables to the secure level S.

[0148] For the number of variables initially available on one iteration step—D>1 (e.g. 10), we can consider sequences of g Boolean vectors (e.g. g=7, s=75). Construct the following sequence of the length 2^(g):

{p ¹ ₂ , p ² ₂ }, {p ₃ ¹¹ , p ₃ ¹² , p ₃ ²¹ , p ₃ ²² }, . . . , {p ^(π(g)) _(g)}, where π(g)=(π₁(g), . . . , π_(g)(g)), and each π_(υ)(g)ε{1,2}.

Here we let p ¹ ₂ =t(p ₁), p ² ₂ =f(p ₁), p ¹¹ ₃ =t(p ₂), p ¹² ₃ =f(p ¹ ₂), p²¹ ₃ =t(p ² ₂), . . . .

[0149] This sequence represents a binary tree. We shall extract all distinct branches from this tree and consider them separately. There are 2^(g) of such branches each one matching the following Boolean condition: ${\overset{g}{\bigwedge\limits_{\rho = 1}}{{\delta (\rho)}{Q\left( p_{\rho} \right)}}},$

[0150] where δ(92 )ε{┐, ┐┐}, here ┐┐ means no negation.

[0151] Comment 10 Using a binary search technique in order to locate all negations can also speed up evaluations of expressions of type ${\overset{g}{\bigwedge\limits_{\rho = 1}}{{\delta (\rho)}{Q\left( p_{\rho} \right)}}},$

[0152] for example:

[0153] Let initially L=1 and u=g,

[0154] Start( ) $\left\{ {{If}\quad \left( {\overset{u}{\bigwedge\limits_{\rho = L}}{Q\left( p_{\rho} \right)}} \right)} \right.$

[0155] return (u, L);/end this call of Start( )/

[0156] Else If $\left. {{(\rceil}{\left( {\bigwedge\limits_{\rho = L}^{\lbrack{u/2}\rbrack}{Q\left( p_{\rho} \right)}} \right)\bigwedge{\bigwedge\limits_{\rho = {{\lbrack{u/2}\rbrack} + L}}^{u}{Q\left( p_{\rho} \right)}}}} \right)$

{([u/2]-L=1)?return (L, L+1); u:=[u/2]; ret=Start( ); store(ret);}

[0157] Else If $\left. {\left( {\bigwedge\limits_{\rho = 1}^{\lbrack{u/2}\rbrack}{{Q\left( p_{\rho} \right)}\bigwedge}} \right\rceil \left( {\bigwedge\limits_{\rho = {{\lbrack{u/2}\rbrack} + L}}^{u}{Q\left( p_{\rho} \right)}} \right)} \right)$

{(u-[u/2]-L=1)?return (u, u−1); L=[u/2]+L; ret:=Start( ); store(ret);}

[0158] Else If $\left. {\left. {{(\rceil}{\left( {\bigwedge\limits_{\rho = L}^{\lbrack{u/2}\rbrack}{Q\left( p_{\rho} \right)}} \right)\bigwedge}} \right\rceil \left( {\bigwedge\limits_{\rho = {{\lbrack{u/2}\rbrack} + L}}^{u}{Q\left( p_{\rho} \right)}} \right)} \right)$

{([u/2]-L=1)?store(L, L+1):{u:=[u/2]; ret:=Start( ); store(ret);};

{([u/2]+L−u=1)?store(u, u−1):{L=[u/2]+1; ret:=Start( ); store(ret)}}

[0159] /Use all returned values to identify the sought expression/

[0160] Such algorithm is evidently very easy to implement on multiple CPUs.

[0161] Part 8: Logical Expression Blending Procedure

[0162] Assume we are given Boolean expressions A and B both in the same fairly general form: ${{\bigwedge\limits_{j}\left( {\bigvee\limits_{k{(j)}}{\delta_{k_{1}}{y_{k_{1}}\bigwedge\delta_{k_{2}}}{y_{k_{2}}\bigwedge\ldots\bigwedge\delta_{k_{d}}}y_{k_{d}}}} \right)} \equiv {\bigwedge\limits_{j}\left( {\bigvee\limits_{k{(j)}}c_{k{(j)}}} \right)}},$

[0163] where as always δ_(k)ε{┐, ┐┐}. We shall make a substitution for each conjunctive term c_(k) by selecting a single variable, with it's negation if the negation is present. Let cA is one of such terms for A and cB is for B, d[A](k, j) is number of factors in cA and d[B](k, j) in cB—for brevity we'll call them just d or d[A] or d[B] with the it's arguments following from context. The steps to “Blend” A and B in a way that in average only exhaustive guessing is possible in order to come up with A and B again, are as follows:

[0164] 1.Replace all C[A]_(k(j)) (FIG. 3.1.1) with δ_(k) ₁ x_(k) ₁

δ_(k) ₂ x_(k) ₂

. . .

δ_(k) _(n) x_(k) _(n) (FIG. 3.1.2) dependent on 2n variables—altogether for all k(j) with fixed j—such that for k≦[d/2] each term is called a free term and all free terms in total depend on n variables I_(f), which we'll call free variables. This we do by computing C[A]_(k(j)) and replacing it:

C[A] _(k(j))=δ_(k) ₁ x _(k) ₁

δ_(k) ₂ x _(k) ₂ . . .

δ_(k) _(n) x _(k) _(n)   (i)

[0165] such that False C[A]_(k(j)) are mapped onto free variables aid True C[A]_(k(j)) onto dependent variables. For k>[d/2] we will have a combination of dependent DT and free terms FT. For DT the sign of every variable must be the same in all terms since all instances of this variable must be true at the same time. This lets us denote DT(k)=True if variable with index k is without negation and DT(k)=False if it's with negation. For the generality sake we assume them all dependent and these terms we'll make dependent on all variables I.

[0166] 2. For each input Boolean vector y={y_(k)} k=1 . . . n let |F(y)| is the number of False values and |T(y)| the number of True values. If |F(y)|<|T(y)| then we use cD*:cD* (┐y_(k))=cD (y_(k)) and we assign z_(k)=┐y_(k), otherwise we use cD (y_(k)). For example if cD=. . .

(┐a

┐b)

. . . =. . .

┐┐(a

┐b) {circumflex over ( )}. . . =. . .

┐(┐a

b)

. . . =. . .

┐ (c

┐d)

. . . =. . .

(┐c

d)

. . . , where c=┐a and b=┐d. And almost identically: . . .

(a

┐b)

. . . =. . .

┐┐(a

┐b)

. . . =. . .

┐(┐a

b)

. . . =. . .

┐(c

┐d)

. . . =. . .

(┐c

d)

. . . .

[0167] 3. Generate d terms for cB (FIG. 3.1.4) by randomly replacing one δ_(k)y_(k) in each term with δ_(k) ₁ x_(k) ₁

δ_(k) ₂ x_(k) ₂ . . .

δ_(k) _(2Log(d)) x_(k) _(2Log(d)) (FIG. 3.1.3) altogether dependent on all I_(f) (FIG. 3.1.5) variables and any needed number of I\I_(f) variables. We essentially repeat step 4, making part of I_(f) dependent (I_(fd)), |I_(fd)|=[n/2] and the other part (I_(f)\I_(fd)) such that each LHS from F(y) will get a matching RHS equal to False. Such RHS will be

δ_(k) ₁ x_(k) ₁

δ_(k) ₂ x_(k) ₂ . . .

δ_(k) _(2Log(d)) x_(k) _(2Log(d))

[0168] where one of the factors will be from (I_(f)\I_(fd)) and equal to False. The rest of the variables can be then taken from anywhere in I including I\I_(f).

[0169] 4. If we see some x_(k) with and without the negation, we treat them as two separate variables from the substitution point of view. Obviously since this remains constant relative to p_(k) we have to take these steps only once and then for each iteration only worry about the values of y_(k) as far as assigning values to the new substitution variables.

[0170] 5. Combine and eliminate terms in cD=cA

cB. When selecting the signs for each variable x_(k) in the substitutions (i) we shall perform a random sign pick so that probability of any given sign being negation next to any variable in (i) in cA or cB is 0.5. Our objective is to have in average less then 1 term for each term in cB conjunctively combined with every term in cA (FIG. 3.2.7). To this end assume we have d terms in cA and each term is n long, if we now take 2Log₂ (d) factors in each term in cB, then in the average we'll find that Log(d) factors in such term already exist in C term—since it contains half of the total number of variables. Now the probability of two random binary vectors of length s being equal is 2^(−s) and so the probability of cA term “survival” after it met cB tern is 1/d and finally in average only 1 final term will be in average produced for each cB term.

[0171] 6. We shall finally assign {x_(k)} for kεI\I_(f) (dependent) to DT[A](k), for kεI_(fd) to DT[B](k) and for kεI_(f)\I_(fd) to False (we use them where RHS is y_(k)εF(y)). The rest of the variables we assign to random constants with respect to {y_(k) } values.

[0172] The result of these steps we'll denote BL(A,B).

[0173] Comment 11 The Blending Procedure above implies an explicit calculation of C[A]_(k(j)) in order to perform substitution (Step 1). This discloses C[A]_(k(j)) shedding some light on A, this is tolerable in case A=RCC. In case of (6.2) for example, α_(j) must be chosen to conjunctively include separate disjunctive factors and disjunctively include separate conjunctive factors (in order to take care of ┐α_(j)).

[0174] Comment 12 The described scheme (Part 1-Part 8) represents a private key only encryption method (not just a one-way function) where the secret key is the expression we are protecting itself. Therefore in general any deciphering algorithm will have to be exhaustive. The protected algorithm will consume all the processing power from the client (some will be still left though) and rarely will need to verify the license, yet it will still not have the most critical part of the program's logic. Arguing this by saying that 'C( ) contains C( ) is just as good as saying that a white sheet of paper contains any word printed in White Ink.

[0175] Comment 13 The protection of the conditions nested in the loops (Part 3 and 4) is suggested as the best mode of operation. This is mainly due to that a sufficient number of variables can be achieved within the Boolean expressions in an automated fashion.

[0176] Also in case with independent processing when secure data preprocessing is possible, the approach described in Part 5 is suggested as more performance effective. 

What is claimed is:
 1. A process of converting a computer program to a form resistant to unauthorized use, whereby said resistant form becomes comprised of a client program, communication channel allowed to have a low bandwidth and be infrequently used and a secure program capable of execution in a time substantially less then the client program comprising the steps of: (a) providing a level of complexity of said computer program's logical conditions such that without knowledge of said logical conditions, determining the logical conditions by a random guess would take prohibitively long time, by means of: (1) combining the logical conditions of said computer program, including those used to control loop execution, so that they achieve substantial length; (2) converting recursive functions to iterative loops; and (3) increasing a number of Boolean variables of said logical conditions in said loops to a sufficiently secure level by means of a loop variable increment procedure (b) providing that said client program contacts said secure program via said communication channel with any desired probability and any of said computer program's input data size by means of: (1) conjunctively adding a random condition controller logical expression to the logical conditions outside of the said computer program loops; (2) converting loops of said computer program to a form where execution of a considerably small set of controlling steps becomes logically necessary to correctly execute other steps whereby said random condition controller conjunctively added to the logical expressions governing said controlling steps, gets invoked a number of times independent of a number of loop iterations said computer program performs; and (3) performing a blending procedure on a plurality of said logical conditions containing said random condition controller to provide a resulting expression whereby separating the random condition controller from said resulting expression would require prohibitively long time; (c) providing means for said program to use input data specific small data packet received from said secure program over said communication channel in order to resume correct execution whereby said client program can execute all instructions of the computer program with an exception of a number of special instructions that is small and independent of an initial input data size whereby said client program will send a small and independent of the initial input data size request and require a small data specific response via said communication channel from said secure program when executing said special instructions whereby said secure program will require an amount of time that is small and independent of initial input data size to generate said data specific response for said client program in case said client program submits said input data with a valid license whereby without knowing said secure program restoring the computer program or otherwise achieving correct execution requires more then a polynomial time. 